COM Server |
All previous examples connected to a COM server. For instance, when we create a Word.Application to manipulate Microsoft Word from a program, we are connecting to a COM server. Creating a COM server is more difficult than connecting to an existing COM server. A COM server is usually located in a DLL and needs to have some information in the computer registry so that program can use it. The figure below shows the Microsoft Word COM server with the two basic interfaces: IUnknown (to request other interfaces) and IDispatch (to execute any function). Clients can connect and use the COM server using these and other interfaces. Todos los ejemplos previos se conectaron a un servidor de COM. Por ejemplo, cuando creamos una Word.Application para manipular Microsoft Word desde un programa, nosotros nos conectamos a un servidor de COM. Crear un servidor de COM es más difícil que conectarse a un servidor existente de COM. Un servidor COM está usualmente localizado en una DLL y necesita tener cierta información en el registro de la computadora para que los programas los puedan usar. La figura de abajo muestra el servidor COM de Microsoft Word con las interfaces básicas: IUnknown (para solicitar otras interfaces) e IDispatch (para ejecutar cualquier función). Los clientes pueden conectase y usar el servidor COM usando estas y otras interfaces. |
Active Template Library (ATL) |
Microsoft created the ATL to simplify the use of COM. ATL is similar to the Standard Templare Library (STL). However, ATL focuses on COM and Windows. We will use the ATL to create a COM server. ATL will perform very complex task in the background to implement the COM server. It is possible to create a COM server without using ATL, however, the programmer will end up writing a lot of code. Microsoft creó la ATL para simplificar el uso de COM. La ATL es muy similar a la Librería de Plantillas Estándar (STL). Sin embargo, ATL se enfoca en COM y en Windows. Nosotros usaremos la ATL para crear un servidor COM. ATL realizará tareas muy complejas por debajo del programador para implementar el servidor de COM. Es posible crear un servidor COM sin usar ATL, sin embargo, el programador terminará escribiendo muchísimo código. |
Interface Definition Language (IDL) |
Microsoft created the IDL to define interfaces. Microsoft Visual Studio compiles IDL files to produce several files used for the COM server. One of this file is a tlb file, the object browser uses a tlb file to display information the library. The figure below shows how the MIDL compiler compiles the IDL file to produced the type library file (*.tlb) and some header files. You can find Windows *.idl and *.h files in the folder C:\Program Files (x86)\Windows Kits\8.1\Include\um . Microsoft creó el IDL para definir interfaces. Microsoft Visual Studio compila los archivos IDL para producir varios archivos para el servidor de COM. Uno de estos archivos es un archivo tlb, el explorador de objetos usa un archivo tlb para mostrar información de la librería. La figura de abajo muestra como el compilador MIDL compila el archivo IDL para producir el archivo de librería de tipos (*.tlb) y algunos archivos de encabezado. Usted puede encontrar los archivos *.idl y *.h de Microsoft Windows en la carpeta C:\Program Files (x86)\Windows Kits\8.1\Include\um . |
CLSID, IID, REFCLSID and REFIID |
In order to indentify a class, COM uses a class ID. A variable of the CLSID type stores the class ID of a COM class. In the same way an IID is used to identify an interface. These variables are numeric values that must be unique. Microsoft Visual Studio provides a tool that creating unique IDs Tools > Create GUID... . It is also possible create a GUID using uuidgen.exe. As these IDs are a number of 128 bits, it is possible to pass these IDs by reference using REFCLSID and REFIID. The code shown below declares a class ID and set its value; remember that these values must be generated using Tools > Create GUID... . When you declare an ID variable (CLSID or IID) in COM, you must initially set its value to GUID_NULL A fin de identificar a una clase, COM usa un ID de clase. Una variable del tipo CLSID almacena el ID de una clase COM. En la misma forma un IID es usado para identificar una interface. Estas variables son valores numéricos que deben ser únicos. Microsoft Visual Studio proporciona una herramienta para crear estos ID únicos Tools > Create GUID... . Es también posible crear GUID usando uuidgen.exe. Como estos ID son números de 128 bits, es posible pasar estos IDs por referencia usando REFCLSID and REFIID. El código mostrado debajo declara un ID para una clase y fija su valor; recuerde que estos valores deben generarse usando: Tools > Create GUID... . Cuando usted declare una variable del tipo ID (CLSID or IID) en COM, usted debe inicializar su valor en GUID_NULL. |
Program.cpp |
void Program::Window_Open(Win::Event& e) { CLSID clsidMain = GUID_NULL; static const CLSID CLSID_IDispatcher = { 0xE69CD190, 0x1276, 0x11D1, 0x9F, 0x64, 0x00, 0xA0, 0xC9, 0x11, 0x00, 0x4F }; } |
IClassFactory |
This interface is very important because it is used to create object. A COM server must implement IClassFactory for each COM class that is included in the library (DLL). The code below shows the declaration of this interface. There are only two methods in the interface, the CreateInstance method is used to create an instance of the object and returns the interface specified by the riid. Esta interface es muy importante porque esta es usada para crear objetos. Un servidor COM debe implementar IClassFactory para cada objeto de la clase COM que está incluido en la librería (DLL). El código de bajo muestra la declaración de esta interface. Hay solamente dos métodos en la interface, el método CreateInstance es usado para crear una instancia del objeto y regresa la interface especificada por el riid. |
IClassFactory.h |
class IClassFactory { public: virtual STDMETHODIMP LockServer(BOOL fLock) = 0; virtual STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void** ppv); }; |
DLL functions |
The COM server is typically hosted in a DLL as shown below. This DLL must implement four basic functions so that COM clients can communicate with the server.
El servidor de COM está usualmente hospedado en una DLL como se muestra en la figura. Esta DLL debe implementar cuatro funciones básicas de tal forma que los clientes se puedan comunicar con el servidor.
|
Problem 1 |
Create a COM server library using ATL. The library will have one COM class called Basic; the class will implement three interfaces as shown below. The library will compute the mean, variance, minimum and maximum of a collection of numeric values. The COM class will have and implement three interfaces: IManager, IStatistics, and IMinMax. The IManager interface will be used to insert values. The IStatistics interface will be used to compute the mean and variance. Finally, the IMinMax interface will be used to compute the minimum value and the maximum value. Microsoft Visual Studio and ATL will help you write the IDL file and other COM server files. Cree una librería en un servidor COM usando ATL. La librería tendrá una clase de COM llamada Basic; la clase implementará tres interfaces como se muestra debajo. La librería calculará la media, la varianza, el mínimo y el máximo de una colección de valores numéricos. La clase COM tendrá e implementará tres interfaces: IManager, IStatistics y IMinMax. La interface IManager será usada para insertar valores. La interface IStatistics será usada para calcular la media y la varianza. Finalmente, la interface IMinMax será usada para calcular el valor mínimo y el valor máximo. Microsoft Visual Studio y ATL nos ayudarán a escribir el archivo IDL y otros archivos del servidor COM. |
Step A |
Open Microsoft Visual Studio, from the menu: FILE > New Project ... > Visual C++ > ATL > ATL project. Do not forget to select DLL. Press the Finish button. Abra Microsoft Visual Studio, desde el menú: FILE > New Project ... > Visual C++ > ATL > ATL project . No se olvide de seleccionar DLL. Presione el botón de Finish. |
Step B |
Use Solution Explorer to review the files generated by the wizard. Use el Explorador de la Solución para revisar los archivos generados por el asistente. |
Step C |
Use Class View to review the classes and functions created by the wizard. Use la Vista de Clases para revisar las clases y las funciones creadas por el asistente. |
Step D |
From Class View open the context menu using the right button of the mouse (do not forget to have selected the main node of your project before making right click). Microsoft Visual Studio 2015: Select Add > Class as shown. Select ATL > ATL Simple Object and press Add. Microsoft Visual Studio 2017: From Solution Explorer, right click Add > New Item > ATL > ATL Simple Object and press Add. Set the name to Basic. Desde la Vista de Clases abra el menú de contexto usando el botón derecho del ratón (no se olvide de tener seleccionado el nodo principal de su proyecto antes de hacer clic con el botón derecho.) Microsoft Visual Studio 2015: Selecione Add > Class como se muestra. Seleccione ATL > ATL Simple Object y presione el botón de Agregar. Microsoft Visual Studio 2017: Desde el Explorador de Archivos, con el botón derecho del ratón Add > New Item > ATL > ATL Simple Object and press Add. Fije el nombre a Basic. |
Step E |
Once the ATL Simple Object Wizard has begun, provide the information of the main class, in this case Basic. The main interface will be IManager. Set an appropriate ProgID. This ProgID will be used by clients to connect to your COM server. Una vez que el asistente de un objeto simple de ATL ha iniciado, proporcione la información de la clase principal, en este caso Basic. La interface principal será IManager. Fije un apropiado ProgID. Este ProgID será usado por los clientes para conectarse a su servidor de COM. |
Tip |
In the ATL Simple Object Wizard Options, you can choose the Interface between: Dual and Custom. If you select Dual, your COM server can be used for all clients including: scripts, Visual Basic, Web pages, programs using #import. If you select Custom, a script client will not be able to use your service. For now, we will use the Custom. En las opciones del asistente de Objeto ATL simple, usted puede escoger la Interface entre: Dual y Custom. Si usted selecciona Dual, su servidor COM podrá ser usado por todos los clientes incluyendo: scripts, Visual Basic, páginas Web, programas usando #import. Si usted selecciona, un cliente con un script no podrá usar su servicio. Por ahora, usaremos Custom. |
Step F |
From Class View select the IManager interface and open the context menu to add the Add method to the interface as shown. You must press Add to add the parameter of the function. When done press the Finish button. Desde la Vista de Clases seleccione la interface IManager y abra el menú de contexto para agregar el método de Add a la interface como se muestra. Usted debe presionar Add para agregar el parámetro de la función. Cuando termine presione el botón de Finalizar. |
Step G |
In the same way add the methods: GetCount and Clear. Your file should look similar to the one shown below, however the uuid values MUST be different as the ones shown below. De la misma forma agregue los métodos: GetCount y Clear. Su archivo debe verse similar al mostrado debajo, sin embargo los valores de la uuid DEBEN ser diferentes a los mostrados debajo. |
MyMath.idl |
// MyMath.idl : IDL source for MyMath // // This file will be processed by the MIDL tool to // produce the type library (MyMath.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; //_______________________________________________________________ IManager [ object, uuid(CA587623-A475-417D-B00E-25059E15E245), nonextensible, pointer_default(unique) ] interface IManager : IUnknown{ [id(1), helpstring("Inserts a new value")] HRESULT Add([in] DOUBLE value); [id(2), helpstring("Returns the number of values")] HRESULT GetCount([out] LONG* count); [id(3), helpstring("Removes all previous values")] HRESULT Clear(void); }; //_______________________________________________________________ MyMathLib [ uuid(3D404682-3FFF-4C9B-8C27-26911884337C), version(1.0), ] library MyMathLib { importlib("stdole2.tlb"); [ uuid(7ECD336B-1C46-44D5-AF1A-18B477FB4B72) ] coclass Basic { [default] interface IManager; }; }; |
Step H |
Add the IStatistics interface. Open the MyMath.idl file and add the IStatistics interface before the IManager interface as shown below, you must generate an GUID using Microsoft Visual Studio Tools > Create GUID... . Do not use the IDs shown in the example. Save your project, and use the menu: Build > Build Solution to build your project. If you are not running Microsoft Visual Studio as administrator, you will get a "Failed to register" error. Do not worry about this error for now. Agregue la interface IStatistics. Abra el archivo MyMath.idl y agregue la interface IStatistics antes de la interface IManager como se muestra debajo, usted debe generar un GUID usando Microsoft Visual Studio Tools > Create GUID... . No se use los IDs mostrados en el ejemplo. Guarde su proyecto y use el menú de Build > Build Solution para construir su proyecto. Si usted no está corriendo Microsoft Visual Studio como administrador, usted obtendrá un error de "Failed to register". No se preocupe por ahora de este error. |
MyMath.idl |
// MyMath.idl : IDL source for MyMath // // This file will be processed by the MIDL tool to // produce the type library (MyMath.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; //_______________________________________________________________ IStatistics [ object, uuid(104A3143-5DC4-45A4-9644-F6244D187E55), nonextensible, pointer_default(unique) ] interface IStatistics : IUnknown{ }; //_______________________________________________________________ IManager ... ... //_______________________________________________________________ MyMathLib [ uuid(3D404682-3FFF-4C9B-8C27-26911884337C), version(1.0), ] library MyMathLib { importlib("stdole2.tlb"); [ uuid(7ECD336B-1C46-44D5-AF1A-18B477FB4B72) ] coclass Basic { [default] interface IManager; interface IStatistics; }; }; |
Step I |
Add the methods GetMean and GetVariance to the IStatistics interface. Agregue los métodos GetMean y GetVariance a la interface IStatistics. |
MyMath.idl |
// MyMath.idl : IDL source for MyMath // // This file will be processed by the MIDL tool to // produce the type library (MyMath.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; //_______________________________________________________________ IStatistics [ object, uuid(104A3143-5DC4-45A4-9644-F6244D187E55), nonextensible, pointer_default(unique) ] interface IStatistics : IUnknown{ [id(1), helpstring("Returns the mean")] HRESULT GetMean([out] DOUBLE* mean); [id(2), helpstring("Returns the variance")] HRESULT GetVariance([out] DOUBLE* variance); }; //_______________________________________________________________ IManager ... ... //_______________________________________________________________ MyMathLib [ uuid(3D404682-3FFF-4C9B-8C27-26911884337C), version(1.0), ] library MyMathLib { importlib("stdole2.tlb"); [ uuid(7ECD336B-1C46-44D5-AF1A-18B477FB4B72) ] coclass Basic { [default] interface IManager; interface IStatistics; interface IMinMax; }; }; |
Step J |
Add the IMinMax interface. Open the MyMath.idl file and add the IMinMax interface before the IStatistics interface as shown below, you must generate an GUID using Microsoft Visual Studio Tools > Create GUID... . Do not use the IDs shown in the example. Save your project, and use the menu: Build > Build Solution to build your project. Agregue la interface IMinMax. Abra el archivo MyMath.idl y agregue la interface IMinMax antes de la interface IStatistics como se muestra debajo, usted debe generar un GUID usando Microsoft Visual Studio Tools > Create GUID... . No se use los IDs mostrados en el ejemplo. Guarde su proyecto y use el menú de Build > Build Solution para construir su proyecto. |
MyMath.idl |
// MyMath.idl : IDL source for MyMath // // This file will be processed by the MIDL tool to // produce the type library (MyMath.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; //_______________________________________________________________ IMinMax [ object, uuid(CC49C6E0-E2CF-4751-AAB1-902A73921D4F), nonextensible, pointer_default(unique) ] interface IMinMax : IUnknown{ }; //_______________________________________________________________ IStatistics [ object, ... //_______________________________________________________________ IManager [ object, ... |
Tip |
Once you have learned the format and syntax of the IDL file, you edit this file without using the respective Wizards. Una vez que usted ha aprendido el formato y la sintaxis del archivo IDL, usted puede editar este archivo sin usar los asistentes respectivos. |
Step K |
Add the methods GetMinimum and GetMaximum to the IMinMax interface. Agregue los métodos GetMinimum y GetMaximum a la interface IMinMax. |
MyMath.idl |
// MyMath.idl : IDL source for MyMath // // This file will be processed by the MIDL tool to // produce the type library (MyMath.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; //_______________________________________________________________ IMinMax [ object, uuid(CC49C6E0-E2CF-4751-AAB1-902A73921D4F), nonextensible, pointer_default(unique) ] interface IMinMax : IUnknown{ [id(1), helpstring("Returns the minimum")] HRESULT GetMinimum([out] DOUBLE* minimum); [id(2), helpstring("Returns the maximum")] HRESULT GetMaximum([out] DOUBLE* maximum); }; //_______________________________________________________________ IStatistics [ object, ... |
Step L |
From Class View select the CBasic class and use the context menu to implement the IStatistics and IMinMax interfaces as shown. The Wizard will edit the files Basic.h and Basic.cpp adding the respective functions of each interface. You CAN edit these file without using the wizard. Desde la Vista de Clases seleccione la clase CBasic y use el menú de contexto para implementar las interfaces IStatistics y IMinMax como se muestra. El asistente editará los archivos Basic.h y Basic.cpp agregados las funciones respectivas de cada interface. Usted PUEDE editar estos archivos sin utilizar el asistente. |
Step M |
Open the Basic.h file and add the following member variables. Do not forget to initialize these variables in the class constructors |
Basic.h |
... //______________________________________________________________ CBasic // Basic.h : Declaration of the CBasic ... //______________________________________________________________ CBasic class ATL_NO_VTABLE CBasic : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CBasic, &CLSID_Basic>, public IManager, public IMinMax, public IStatistics { private: int count; double sum; double sq_sum; double minimum; double maximum; public: CBasic() { count = 0; sum = 0.0; sq_sum = 0.0; minimum = 0.0; maximum = 0.0; } ... |
Step N |
Edit the Basic.h file to write the code of the methods of the interfaces: IStatistics and IMinMax. Edite el archivo Basic.h para escribir el código de los métodos de las interfaces: IStatistics and IMinMax. |
Basic.h |
... public: STDMETHOD(Add)(DOUBLE value); STDMETHOD(GetCount)(LONG* count); STDMETHOD(Clear)(void); //_______________________________________________________IMinMax public: STDMETHOD(GetMinimum)(DOUBLE * minimum) { *minimum = this->minimum; return S_OK; } STDMETHOD(GetMaximum)(DOUBLE * maximum) { *maximum = this->maximum; return S_OK; } //______________________________________________________ IStatistics public: STDMETHOD(GetMean)(DOUBLE * mean) { *mean = sum/count; return S_OK; } STDMETHOD(GetVariance)(DOUBLE * variance) { *variance = sq_sum/(count-1) - (sum*sum)/(count*(count-1)); return S_OK; } }; OBJECT_ENTRY_AUTO(__uuidof(Basic), CBasic) |
Step O |
Open and edit the Basic.cpp file to write the code of the IManager methods. Abra y edite el archivo Basic.cpp para escribir el código de los métodos de IManager. |
Basic.cpp |
// Basic.cpp : Implementation of CBasic #include "stdafx.h" #include "Basic.h" //________________________________________________________________________ IManager STDMETHODIMP CBasic::Add(DOUBLE value) { sum += value; sq_sum += (value*value); // if (count == 0) { minimum = value; maximum = value; } else { if (value < minimum) minimum = value; if (value > maximum) maximum = value; } count++; return S_OK; } STDMETHODIMP CBasic::GetCount(LONG* count) { *count = this->count; return S_OK; } STDMETHODIMP CBasic::Clear(void) { count = 0; sum = 0.0; sq_sum = 0.0; minimum = 0.0; maximum = 0.0; return S_OK; } |
Step P |
Your MyMath.idl file should look similar to the one shown below. Su archivo MyMath.idl debería verse similar al mostrado debajo. |
MyMath.idl |
// MyMath.idl : IDL source for MyMath // // This file will be processed by the MIDL tool to // produce the type library (MyMath.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; //_______________________________________________________________ IMinMax [ object, uuid(CC49C6E0-E2CF-4751-AAB1-902A73921D4F), nonextensible, pointer_default(unique) ] interface IMinMax : IUnknown{ [id(1), helpstring("Returns the minimum")] HRESULT GetMinimum([out] DOUBLE* minimum); [id(2), helpstring("Returns the maximum")] HRESULT GetMaximum([out] DOUBLE* maximum); }; //_______________________________________________________________ IStatistics [ object, uuid(104A3143-5DC4-45A4-9644-F6244D187E55), nonextensible, pointer_default(unique) ] interface IStatistics : IUnknown{ [id(1), helpstring("Returns the mean")] HRESULT GetMean([out] DOUBLE* mean); [id(2), helpstring("Returns the variance")] HRESULT GetVariance([out] DOUBLE* variance); }; //_______________________________________________________________ IManager [ object, uuid(CA587623-A475-417D-B00E-25059E15E245), nonextensible, pointer_default(unique) ] interface IManager : IUnknown{ [id(1), helpstring("Inserts a new value")] HRESULT Add([in] DOUBLE value); [id(2), helpstring("Returns the number of values")] HRESULT GetCount([out] LONG* count); [id(3), helpstring("Removes all previous values")] HRESULT Clear(void); }; //_______________________________________________________________ MyMathLib [ uuid(3D404682-3FFF-4C9B-8C27-26911884337C), version(1.0), ] library MyMathLib { importlib("stdole2.tlb"); [ uuid(7ECD336B-1C46-44D5-AF1A-18B477FB4B72) ] coclass Basic { [default] interface IManager; interface IStatistics; interface IMinMax; }; }; |
Step Q |
Change the configuration to Release and Rebuild the solution. The MyMath.dll file will be created at MyMath\Release folder. The MyMath.tlb file will be created at MyMath\MyMath\Release. Create a new permanent folder to install your library, and then, copy the DLL and TLB files to this folder as shown. The MyMath.tlb file may be located somewhere else in your project. Cambie la configuración a Release y Reconstruya la solución. El archivo MyMath.dll será creado en la carpeta de MyMath\Release. El archivo MyMath.tlb será creado en MyMath\MyMath\Release. Cree una carpeta permanente para instalar su librería, y entonces, copie la DLL y la TLB a este folder como se muestra. El archivo MyMath.tlb puede ser ubicado en algún otro lugar en su proyecto. |
Step R |
Open a CMD window as administrator (use the context menu to run CMD as administrator), and navigate to the folder where the MyMath.dll was copied. Register the library as shown. To remove the library from the computer registry, you can use regsvr32 -u MyMath.dll Abra una ventana de CMD como administrador (use el menú de contexto para ejecutar CMD como administrador), y navegue a la carpeta donde se colocó MyMath.dll. Registre la librería como se muestra. Para remover la librería del registro de la computadora, usted puede usar regsvr32 -u MyMath.dll |
MSDOS: cmd.exe |
Microsoft Windows [Version 6.1.7601] Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:\windows\system32>cd.. C:\Windows>cd.. C:\>cd MyMath C:\MyMath>cd Release C:\MyMath\Release\regsvr32 MyMath.dll |
Problem 2 |
Create a Wintempla dialog application called MathTest to test the COM server created in the previous problem. You can see your library in the Object Browser to verify that your library was properly registered (To open the Object Browser use the Menu: View > Object Browser click on the three dots to choose the library). You cannot un-registered the library if the Object Browser is used for browsing the library. Cree una aplicación de Wintempla de diálogo llamada MathTest para probar el servidor COM creado en el problema previo. Usted puede ver su librería en el Explorador de Objetos para verificar que su librería quedo registrada. (Para abrir el Object Brower use el menu: View > Object Browser haga click en los tres puntos para seleccionar la librería.) Usted no puede eliminar la librería del registro si el Object Browser es usado para navegar la librería. |
Step A |
We will import now out COM library to produce the respective header files, we can import the dll file or the tlb file. Add the following line at the end of the stdafx.h file. Compile the project. Move the MyMath.tlh and MyMath.tli files from the Debug folder to the MathTest project folder. After this, you can remove the import command from the stdafx.h file. Nosotros importaremos ahora nuestra librería COM para producir los archivos respectivos de encabezado, usted puede importar el archivo dll o el archivo tlb. Agregue la siguiente línea al final del archivo stdafx.h. Compile el proyecto. Mueva los archivos MyMath.tlh y MyMath.tli desde la carpeta de Debug a la carpeta del proyecto MathTest. Después de esto, usted puede eliminar la línea con el comando de import del archivo stdafx.h. |
stdafx.h |
... #import "C:\\MyMath\\Release\\MyMath.dll" |
Step B |
From Solution Explorer add the mymath.tlh and mymath.tli files using the context menu. In some cases, the mymath.tlh file WILL not have the correct path for the myMath.tli file. Open the mymath.tlh file and check the #include "mymath.tli" path at the end of the file. Desde el Explorador de Soluciones agregue los archivos mymath.tlh y mymath.tli usando el menú de contexto. En algunos casos, el archivo mymath.tlh NO TENDRÁ el path correcto para el archivo myMath.tli. Abra el archivo mymath.tlh y verifique el path en #include "mymath.tli" al final del archivo. |
MathTest.h |
#pragma once //______________________________________ MathTest.h #include "Resource.h" //#include "mymath.tlh" //#include "mymath.tli" class MathTest: public Win::Dialog { public: MathTest() { ::CoInitialize(NULL); } ~MathTest() { ::CoUninitialize(); } protected: ... }; |
MathTest.cpp |
... void MathTest::Window_Open(Win::Event& e) { MyMathLib::IManagerPtr manager; MyMathLib::IStatisticsPtr statistics; MyMathLib::IMinMaxPtr minmax; HRESULT hr; wstring text; Com::Exception ex; double minimum = 0.0, maximum = 0.0, mean = 0.0, variance = 0.0; try { //______________________________________________ CreateInstance hr = manager.CreateInstance(L"selo.Basic"); ex.ok(L"manager.CreateInstance", hr); // manager->Add(10.0); manager->Add(8.0); manager->Add(2.0); manager->Add(5.0); //____________________________________________ Get IStatistics and IMinMax statistics = manager; minmax = manager; // statistics->GetMean(&mean); statistics->GetVariance(&variance); minmax->GetMinimum(&minimum); minmax->GetMaximum(&maximum); Sys::Format(text, L"mean = %g\r\nvar = %g\r\nmin = %g\r\nmax = %g", mean, variance, minimum, maximum); this->MessageBox(text, L"MathTest", MB_OK); } catch(Com::Exception& excep) { excep.Display(hWnd, L"MathTest"); } catch(_com_error excep) { Com::Exception::Display(hWnd, excep, L"MathTest"); } } |
Step C |
Remove the library from the registry. Do not forget to run CMD as administrator. Be sure to remove your library from the Object Browser (by clicking in the three dots in the Object Browser, otherwise, you will not be able to remove the MyMath.dll file. Remueva la librería del registro. No se olvide de ejecutar CMD como administrador. Asegúrese de remover la librería en el Object Browser (haciendo clic en los tres puntos del Object Browser), de otro modo, usted no podrá borrar el archivo MyMath.dll. |
MSDOS: cmd.exe |
Microsoft Windows [Version 6.1.7601] Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:\windows\system32>cd.. C:\Windows>cd.. C:\>cd MyMath C:\MyMath>cd Release C:\MyMath\Release>regsvr32 -u MyMath.dll C:\MyMath\Release> |
Dual Interfaces |
There are two types of clients in COM: script clients and regular clients. Examples of script clients are: VBScript and Javascript. A C++ program using the #import command is a regular client. Script clients are regularly Web Browsers such as Internet Explorer, but you can use scripts in other situations. A C++ program that does not use the #import command can be considered a script client. Script clients require a standard interface called IDispatch to operate. A dual interface is an interface that implements one custom interface (for regular clients) and the IDispatch interface (for script clients). Hay dos tipos de clientes en COM: clientes script y clientes regulares. Ejemplos de clientes del tipo scripts son: VBScript y Javascript. Un programa en C++ usando el comando #import es un cliente regular. Los clientes del tipo scripts son usados regularmente en las Exploradores Web tal como Internet Explorer, pero usted puede usar scripts en otras situaciones. Un programa en C++ que no usa el comando #import puede ser considerado un cliente del tipo scripts. Los clientes del tipo scripts requieren una interface estándar llamada IDispatch para operar. Una interface dual es una interface que implementa una interface personalizada (para los clientes regulares) y la interface IDispatch (para los clientes del tipo scripts). |
Default Interface |
A default interface is the interface that is received at the moment at object is created. Scripts clients can only see the default interface. Each class must have only one dual interface, thus, the dual interface must be declared as the default interface so that script client can use the class. The dual interface MUST include all functions of non-default interfaces so that scripts clients can call all functions of the class. Una interface de default es la interface que se recibe al momento que el objeto es creado. Los clientes del tipo scripts pueden solamente ver la interface de default. Cada clase debe tener solamente una interface dual, así, la interface dual debe ser declarada como la interface de default de tal forma que los clientes del tipo script puede usar la clase. La interface dual DEBE incluir todas las funciones de las interfaces que no son default de tal forma que los clientes del tipo script pueden llamar todas las funciones de la clase. |
Problem 3 |
Open the MyMath.idl file in the MyMath solution. Add manually the IMathFunc interface, be sure to declare this interface as dual, and declare IMathFunc as the default interface. Remember to generate an ID for this new interface; do not use the value shown. The only dual interface must be IMathFunc. Observe the IMathFunc interface is derived from IDispatch. Abra el archivo MyMath.idl de la solución MyMath. Agregue manualmente la interface IMathFunc , asegúrese de declarar esta interface como dual, y declare IMathFunc como la interface de default. Recuerde de generar un ID para esta nueva interface; no use el valor mostrado. La única interface dual debe ser IMathFunc. Observe que la interface IMathFunc esta derivada de IDispatch. |
MyMath.idl. |
// MyMath.idl : IDL source for MyMath // // This file will be processed by the MIDL tool to // produce the type library (MyMath.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; //_______________________________________________________________ IMathFunc [ object, uuid(98206AF3-5570-4061-8A3C-30A69CA107D9), dual, nonextensible, pointer_default(unique) ] interface IMathFunc : IDispatch{ //________________________________________ IMinMax [id(1), helpstring("Returns the minimum")] HRESULT GetMinimum([out] DOUBLE* minimum); [id(2), helpstring("Returns the maximum")] HRESULT GetMaximum([out] DOUBLE* maximum); //________________________________________ IStatistics [id(3), helpstring("Returns the mean")] HRESULT GetMean([out] DOUBLE* mean); [id(4), helpstring("Returns the variance")] HRESULT GetVariance([out] DOUBLE* variance); //________________________________________ IManager [id(5), helpstring("Inserts a new value")] HRESULT Add([in] DOUBLE value); [id(6), helpstring("Returns the number of values")] HRESULT GetCount([out] LONG* count); [id(7), helpstring("Removes all previous values")] HRESULT Clear(void); }; //_______________________________________________________________ IMinMax ... //_______________________________________________________________ IStatistics ... //_______________________________________________________________ IManager ... //_______________________________________________________________ MyMathLib [ uuid(3D404682-3FFF-4C9B-8C27-26911884337C), version(1.0), ] library MyMathLib { importlib("stdole2.tlb"); [ uuid(7ECD336B-1C46-44D5-AF1A-18B477FB4B72) ] coclass Basic { [default] interface IMathFunc; interface IManager; interface IStatistics; interface IMinMax; }; }; |
Step A |
Edit Basic.cpp file. You need to implement the IMathFunc interface, you already have all the functions;
Edit el archivo Basic.cpp. Usted necesita implementar la interface IMathFunc, usted ya tiene todas las funciones;
|
Basic.h |
... //______________________________________________________________ CBasic class ATL_NO_VTABLE CBasic : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CBasic, &CLSID_Basic>, public IDispatchImpl<IMathFunc, &__uuidof(IMathFunc), &LIBID_MyMathLib, /* wMajor = */ 1, /* wMinor = */ 0>, public IManager, public IMinMax, public IStatistics { private: int count; double sum; double sq_sum; double minimum; double maximum; public: CBasic() { count = 0; sum = 0.0; sq_sum = 0.0; minimum = 0.0; maximum = 0.0; } DECLARE_REGISTRY_RESOURCEID(IDR_BASIC) BEGIN_COM_MAP(CBasic) COM_INTERFACE_ENTRY(IManager) COM_INTERFACE_ENTRY2(IDispatch, IMathFunc) COM_INTERFACE_ENTRY(IMinMax) COM_INTERFACE_ENTRY(IStatistics) END_COM_MAP() ... |
Step B |
Build your project and register the MyMath.dll library. Then, use the Object Browser to check that the Basic class includes all seven functions. Compile su proyecto y registre la librería MyMath.dll. Entonces, usa el Object Browser para verificar que la clase Basic incluye todas las siete funciones. |
Step C |
Create a Wintempla project called ScriptTest to test the Math library from without using import. Cree un proyecto de Wintempla llamado ScriptTest para probar la librería Math sin usar el comando import. |
ScriptTest.h |
#pragma once //______________________________________ ScriptTest.h #include "Resource.h" class ScriptTest: public Win::Dialog { public: ScriptTest() { ::CoInitialize(NULL); } ~ScriptTest() { ::CoUninitialize(); } protected: ... }; |
ScriptTest.cpp |
... void ScriptTest::Window_Open(Win::Event& e) { Com::Object mathFunc; _variant_t result; //________________________ mean double mean = 0.0; _variant_t vmean; vmean.vt = VT_R8 | VT_BYREF; vmean.pdblVal = &mean; //________________________ variance double variance = 0.0; _variant_t vvariance; vvariance.vt = VT_R8 | VT_BYREF; vvariance.pdblVal = &variance; //________________________ minimum double minimum = 0.0; _variant_t vminimum; vminimum.vt = VT_R8 | VT_BYREF; vminimum.pdblVal = &minimum; //________________________ maximum double maximum = 0.0; _variant_t vmaximum; vmaximum.vt = VT_R8 | VT_BYREF; vmaximum.pdblVal = &maximum; wstring text; try { mathFunc.CreateInstance(L"selo.Basic", true); //Com::Container::DisplayInterfaceFunctions(hWnd, mathFunc); // mathFunc.Method(L"Add", 10.0, result); mathFunc.Method(L"Add", 8.0, result); mathFunc.Method(L"Add", 2.0, result); mathFunc.Method(L"Add", 5.0, result); // mathFunc.Method(L"GetMean", vmean, result); mathFunc.Method(L"GetVariance", vvariance, result); mathFunc.Method(L"GetMinimum", vminimum, result); mathFunc.Method(L"GetMaximum", vmaximum, result); Sys::Format(text, L"mean = %g\r\nvar = %g\r\nmin = %g\r\nmax = %g", mean, variance, minimum, maximum); this->MessageBox(text, L"MathTest", MB_OK); } catch(Com::Exception excep) { excep.Display(hWnd, L"ScriptTest"); } } |
Method vs. Property |
In the MyMath.dll library, GetMean was declared as a method making difficult to pass a pointer to a double value. To simplify the code, GetMean should have been declared as a get property as it is shown in the figures below. En la librería MyMath.dll, GetMean fue declarado como un método haciendo difícil pasar un puntero a un valor double. Para simplificar el código, GetMean se debió haber declarado como una propiedad del tipo get como es mostrado en las figuras siguientes. |
Tip |
You may be interested in exploring the ATL Wizards to create a COM control (ActiveX) or other projects. Macromedia Flash Player is an ActiveX control that is used to display multimedia content in a web page. The Java plug-in in a web page is also an ActiveX control. Lab View and other products create their own ActiveX controls to be used for COM clients. Usted puede estar en explorar los asistentes de ATL para crear un control COM (ActiveX) u otro tipo de proyectos. El reproductor Flash de Macromedia es un ActiveX control que es usado para mostrar contenido de multimedia en una página web. El plug-in de Java en un página web es también un ActiveX control. Lab View y otros productos crean sus propios controles ActiveX para ser usados por clientes COM. |
ATL Headers |
The following header file shows the required header files to use ATL. El siguiente archivo de encabezado muestra los archivos de encabezado requeridos para usar ATL. |
Program.h |
//_______________________________ Header for ATL #include <atlbase.h> #include <atlcom.h> #include <atlctl.h> using namespace ATL; |
ATL COM templates |
|